package com.spring.util;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @ClassName ServiceUtil
 * @Description TODO
 * @Author ZhaoKai
 * @Date 2022-02-1616:02
 * @Version 1.0
 **/
@Aspect
@Component
public class ServiceUtil {
    /**
     * 前置通知
     **/
    @Before(value = "execution(* *..StudentImpl.*(..))")
    public static void doBefore() {
        System.out.println("时间：" + new Date());
    }

    /**
     * 最终通知
     */
    @After(value = "pointcut()")
    public static void doAfter() {
        System.out.println("doAfter：ServiceUtil.doAfter");
    }

    /**
     * 可以接收返回参数的后置通知
     *
     * @param joinPoint 必须位于第一个位置，里面包含了执行方法的相关信息
     * @param res       目标方法返回值
     *                  修改目标方法返回值，不影响原有返回值
     */
    @AfterReturning(value = "pointcut()", returning = "res")
    public static void doAfterReturning(JoinPoint joinPoint, Object res) {
        System.out.println("doAfterReturning: " +
                joinPoint.getSignature().getDeclaringTypeName() + "." +
                joinPoint.getSignature().getName() + " " +
                "res: " + res.toString());
    }

    /**
     * 环绕通知
     *
     * @param joinPoint 特点：
     *                  1、功能最强的通知
     *                  2、目标方法前后都可以增强功能
     *                  3、控制目标方法是否被执行
     *                  4、修改原来的 目标方法返回结果，影响调用结果
     *                  等同于JDK中InvocationHandler接口
     */
    @Around(value = "pointcut()")
    public static Object doAround(ProceedingJoinPoint joinPoint) {

        /*
          实现
           1、调用目标方法
           2、在目标方法前后增强功能
         */
        Object res = null;
        System.out.println("doAround:目标方法执行前，输出时间：" + new Date());
        try {
            res = joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("doAround:目标方法执行后提交事务");

        if (res != null) {
            res = 20;
        }
        return res;
    }

    /**
     * @Pointcut: 定义和管理切入点表达式，项目中存在多个切入点表达式一致，可以用@Pointcut这个可以复用的
     * 当使用Pointcut时，此时这个方法的名称就可以作为切入点表达式的别名
     * 在其他的通知中，可以使用这个方法的名称
     */
    @Pointcut(value = "execution(* *..StudentImpl.*(..))")
    public void pointcut() {

    }
}
